///@file MaterialPoint
///@brief Implementation of the class defining a material point
///@author Arnaud Duval
///@version 0.0
///@date 2010/03/25

#include "MaterialPoint.h"


///@brief Default constructor
MaterialPoint::MaterialPoint()
{
    nbIntVar = 0;
    dim = 0;
}

///@brief Constructor with arguments
///@param dmat Pointer to affected material
///@param nb Number of internal variables
MaterialPoint::MaterialPoint(Material* dmat, unsigned int nb)
{
	mat = dmat;
	nbIntVar = nb;
	internalVar = new double[nbIntVar];
	intVarLabels = new std::string[nbIntVar];
}

///@brief Copy constructor
///@param p MaterialPoint object to copy
MaterialPoint::MaterialPoint(const MaterialPoint & p)
{
    mat = p.mat;
    nbIntVar = p.nbIntVar;
    if(nbIntVar > 0)
    {
        internalVar = new double[nbIntVar];
        intVarLabels = new std::string[nbIntVar];
        for(unsigned int i = 0 ; i < nbIntVar ; i++)
        {      
            internalVar[i] = p.internalVar[i];
            intVarLabels[i] = p.intVarLabels[i];
        }
    }
    stress = p.stress;
    strain = p.strain;
    T = p.T;
    dim = p.dim;
    if(dim > 0)
    {
        refCoords = new double[dim];
        structCoords = new double[dim];
        for(unsigned int i = 0 ; i < dim ; i++)
        {
            refCoords[i] = p.refCoords[i];
            structCoords[i] = p.structCoords[i];
        }
    }
}

///@brief Destructor
MaterialPoint::~MaterialPoint()
{
    if(nbIntVar != 0)
    {
        delete[] internalVar;
        delete[] intVarLabels;
    }
    mat = NULL;
    if(dim != 0)
    {
        delete[] structCoords;
        delete[] refCoords;
    }
}

///@brief Overload of = operator
///@param p Right hand operand
MaterialPoint& MaterialPoint::operator=(const MaterialPoint& p)
{
    mat = p.mat;
    nbIntVar = p.nbIntVar;
    if(nbIntVar > 0)
    {
        internalVar = new double[nbIntVar];
        intVarLabels = new std::string[nbIntVar];
        for(unsigned int i = 0 ; i < nbIntVar ; i++)
        {
            internalVar[i] = p.internalVar[i];
            intVarLabels[i] = p.intVarLabels[i];
        }
    }
    stress = p.stress;
    strain = p.strain;
    T = p.T;
    dim = p.dim;
    if(dim > 0)
    {
        refCoords = new double[dim];
        structCoords = new double[dim];
        for(unsigned int i = 0 ; i < dim ; i++)
        {
            refCoords[i] = p.refCoords[i];
            structCoords[i] = p.structCoords[i];
        }
    }
    return (*this);
}

///@brief Direct access to temperature
double& MaterialPoint::Temperature()
{
	return T;
}

///@brief Direct access to stress state
StressTensor& MaterialPoint::Stress()
{
	return stress;
}
///@brief Direct access to strain state
StrainTensor& MaterialPoint::Strain()
{
	return strain;
}

///@brief Direct access to an internal variables
///@param n Index of internal variable to return (index 1 for the first variable)
double& MaterialPoint::IntVar(unsigned int n)
{
	assert(n > 0);
	assert(n <= nbIntVar);
	return internalVar[n-1];
}

///@brief Direct access to the label of an internal variables
///@param n Index of internal variable label to return (index 1 for the first variable)
std::string& MaterialPoint::IntVarlabel(unsigned int n)
{
	assert(n > 0);
	assert(n <= nbIntVar);
	return intVarLabels[n-1];
}

///@brief Set the material
///@param theMaterial pointer to the material to be set
void MaterialPoint::SetMaterial(Material *theMaterial)
{
    mat = theMaterial;
}

///@brief Return coordinate in the reference element
///@param idx Index of the coordinate to return (starts at 1)
double MaterialPoint::GetRefCoord(unsigned int idx)
{
    assert((idx > 0)&&(idx <= dim));
    return refCoords[idx - 1];
}
        
///@brief Return coordinate in the structural element
///@param idx Index of the coordinate to return (starts at 1)
double MaterialPoint::GetStructCoord(unsigned int idx)
{
    assert((idx > 0)&&(idx <= dim));
    return structCoords[idx -1];
}

///@brief Set the coordinate in the reference element
///@param idx Index of the coordinate to set (starts at 1)
///@param coord Value of the coordinate to set
void MaterialPoint::SetRefCoord(unsigned int idx, double coord)
{
    assert((idx > 0)&&(idx <= dim));
    refCoords[idx - 1] = coord;
}

///@brief Set the dimension of the MaterialPoint
///@param d New dimenion of the material point
void MaterialPoint::SetDimension(unsigned int d)
{
    if(dim != d)
    {
        if(dim != 0)
        {
            delete[] refCoords;
            delete[] structCoords;
        }
        refCoords = new double[d];
        structCoords = new double[d];
        dim = d;
    }
}